package com.three.common;

import com.three.api.MessageHandler;
import com.three.api.PacketReceiver;
import com.three.api.connection.Connection;
import com.three.api.connection.SessionContext;
import com.three.api.protocol.Packet;
import com.three.common.handler.BaseMessageHandler;
import com.three.common.handler.MessageBaseHandler;
import com.three.common.message.base.BaseMessage;
import com.three.common.message.base.ErrorMessage;
import com.three.common.receiver.IReceiver;
import com.three.protocol.CommandEnum;
import com.three.tools.common.Profiler;
import com.three.utils.LogUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import static com.three.common.ErrorCode.DISPATCH_ERROR;
import static com.three.common.ErrorCode.UNSUPPORTED_CMD;

/**
 * 消息调度类
 * Created by Mathua on 2017/5/26.
 */
public final class MessageDispatcher implements PacketReceiver {
    public static final int POLICY_REJECT = 2;
    public static final int POLICY_LOG = 1;
    public static final int POLICY_IGNORE = 0;
    private static final Logger LOGGER = LoggerFactory.getLogger(MessageDispatcher.class);
    private final Map<Short, MessageHandler> handlers = new HashMap<>();
    private final int unsupportedPolicy;

    public MessageDispatcher() {
        unsupportedPolicy = POLICY_REJECT;
    }

    public MessageDispatcher(int unsupportedPolicy) {
        this.unsupportedPolicy = unsupportedPolicy;
    }

    public void register(CommandEnum.Command command, MessageHandler handler) {
        MessageHandler old = handlers.putIfAbsent((short) command.getNumber(), handler);
        if(old != null) {
            LOGGER.error("msg register error, register repeat, msgId:{}", command);
        }
    }

    @Override
    public void onReceive(Packet packet, Connection connection) {
        MessageHandler handler = handlers.get(packet.cmd);
        if (handler != null) {
            Profiler.enter("time cost on [dispatch]");
            try {
                // 只检验客户端发过来的信息
                if(this == IReceiver.connectionServerReceiver || this == IReceiver.webSocketServerReceiver) {
                    if( handler instanceof MessageBaseHandler) {
                        MessageBaseHandler baseHandler = (MessageBaseHandler) handler;
                        SessionContext context = connection.getSessionContext();
                        // 如果需要验证但是却没握手成功，则不处理这个包
                        if(baseHandler.isShouldVerifyIdentity() && !context.handshakeOk()) {
                            ErrorMessage.from(packet, connection).setReason("Illegal Operation.").close();
                            return;
                        }
                    }
                }
                handler.handle(packet, connection);
            } catch (Throwable throwable) {
                LOGGER.error("dispatch message ex, packet={}, connect={}, body={}"
                        , packet, connection, Arrays.toString(packet.body), throwable);
                LogUtils.CONN.error("dispatch message ex, packet={}, connect={}, body={}, error={}"
                        , packet, connection, Arrays.toString(packet.body), throwable.getMessage());
                ErrorMessage
                        .from(packet, connection)
                        .setErrorCode(DISPATCH_ERROR)
                        .send();
//                        .close();
            } finally {
                Profiler.release();
            }
        } else {
//            if (unsupportedPolicy > POLICY_IGNORE) {
//                LogUtils.CONN.error("dispatch message failure, cmd={} unsupported, packet={}, connect={}, body={}"
//                        , CommandEnum.Command.valueOf(packet.cmd), packet, connection);
//                if (unsupportedPolicy == POLICY_REJECT) {
//                    ErrorMessage
//                            .from(packet, connection)
//                            .setErrorCode(UNSUPPORTED_CMD)
//                            .close();
//                }
//            }
        }
    }
}
